﻿// <copyright file="SWMM5TextRainSource.cs" company="City of Portland, BES-ASM">
// </copyright>
// <summary>SWMM5TextRainSource class</summary>

namespace BESASM.EMGAATS.DataAccess
{
  using System;
  using System.Collections.Generic;
  using System.IO;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using SystemWrapper;
  using BESASM.EMGAATS.BusinessClasses;

  /// <summary>
  /// Represents a SWMM 5 Text rainfall file
  /// </summary>
  public class SWMM5TextRainSource : IRainSource
  {
    private SystemWrapper.IO.IStreamReaderWrap sourceFile;
    private string currentLine;
    private Dictionary<int, IPoint> locations = new Dictionary<int, IPoint>();

    /// <summary>
    /// Initializes a new instance of the <see cref="SWMM5TextRainSource"/> class
    /// </summary>
    /// <param name="textFile">The name of the text rainfall file</param>
    public SWMM5TextRainSource(SystemWrapper.IO.IStreamReaderWrap textFile)
    {
      this.sourceFile = textFile;
      if (this.sourceFile == null)
      {
        throw new NullReferenceException("File does not exist");
      }
      
      if (this.sourceFile.EndOfStream)
      {
        throw new EndOfStreamException("Empty rainfall file");
      }

      // Read raingage locations
      this.currentLine = this.sourceFile.ReadLine();
      while (this.currentLine[0] == ';')
      {
        string rawLine = this.currentLine.Trim(new char[] { ';', ' ' });

        string[] tokens = rawLine.Split(new char[] { ' ' });
        if (tokens.Length == 3)
        {
          this.locations.Add(
            Convert.ToInt32(tokens[0]), 
            new RaingageLocation(Convert.ToDouble(tokens[1]), Convert.ToDouble(tokens[2])));
        }

        if (!this.sourceFile.EndOfStream)
        {
          this.currentLine = this.sourceFile.ReadLine();
        }
        else
        {
          throw new EndOfStreamException("Raingages present, but no data");
        }
      }
    }

    /// <summary>
    /// Gets the map of raingage IDs and their corresponding point locations
    /// </summary>
    public Dictionary<int, IPoint> Locations
    {
      get 
      {
        return this.locations;
      }
    }

    /// <summary>
    /// Gets the list of raingage IDs
    /// </summary>
    public List<int> LocationIDs
    {
      get 
      {
        var ids = (from l in this.locations
                   orderby l.Key
                   select l.Key).Distinct();
        return ids.ToList();
      }
    }

    /// <summary>
    /// Gets the enumeration of hyetograph points for the raingage
    /// </summary>
    /// <param name="raingage">The raingage ID of interest</param>
    /// <returns>The enumeration of hyetograph points</returns>
    public IEnumerable<HyetographPoint> Rainfall(int raingage)
    {
      while (!this.sourceFile.EndOfStream)
      {
        string[] tokens = this.currentLine.Split(new char[] { ' ', ',', '\t' });

        if (tokens.Length == 7)
        {
          int gage, year, month, day, hour, minute;
          double rainfall;
          bool gageParsed = int.TryParse(tokens[0], out gage);
          if (gageParsed && gage == raingage)
          {
            bool yearParsed = int.TryParse(tokens[1], out year);
            bool monthParsed = int.TryParse(tokens[2], out month);
            bool dayParsed = int.TryParse(tokens[3], out day);
            bool hourParsed = int.TryParse(tokens[4], out hour);
            bool minuteParsed = int.TryParse(tokens[5], out minute);
            bool rainfallParsed = double.TryParse(tokens[6], out rainfall);

            if (yearParsed && monthParsed && dayParsed && hourParsed && minuteParsed &&
              rainfallParsed)
            {
              DateTime pointDate = new DateTime(year, month, day, hour, minute, 0);
              yield return new HyetographPoint(pointDate, rainfall);
            }
          }
        }

        this.currentLine = this.sourceFile.ReadLine();
      }
    }
  }
}
